#pragma once
#include "apoccommon.h"
#include "apocutf8.h"

namespace Apoc
{
  template <typename Pointer>
  inline UInt CountString(Pointer string)
  {
    UInt c = 0;
    while (*string != '\0')
    {
      ++c;
      ++string;
    }

    return c;
  }

  template <typename Pointer>
  inline void ReverseString(Pointer string, Pointer reversedString)
  {
    UInt length = CountString(string);

    for (Pointer p = string + length; p > string; --p)
      *reversedString++ = *p;
    
    *reversedString = '\0';
  }

  template <typename Pointer>
  inline void ReverseString(Pointer string)
  {
    UInt length = CountString(string);

    for (UInt i = 0; i < length/2; ++i)
    {
      auto temp = string[length - i - 1];
      string[length - i - 1] = string[i];

      string[i] = temp;
    }
  }

  template <typename T, typename Pointer, UInt Base>
  inline Pointer IntToString(T integer, Pointer string)
  {
    Pointer p = string;
    do
    {
      auto digit = integer % Base;
      digit += (digit > 9 ? 'A' - 10 : '0');
      *p++ = digit;
    } while ((integer /= Base) > 0);

    *p = '\0';

    ReverseString(string);

    return string;
  }

  template <typename Pointer>
  inline Int8* ToASCII(Pointer string, Int8* out)
  {
    while (*string != '\0')
    {
      *out = (Int8)*string;
      ++out;
      ++string;
    }

    *out = '\0';

    return out;
  }

  template <typename T, typename Pointer>
  inline Pointer IntToDecimalString(T integer, Pointer string)
  { return IntToString<T, Pointer, 10>(integer, string); }

  template <typename T, typename Pointer>
  inline Pointer IntToHexadecimalString(T integer, Pointer string)
  { return IntToString<T, Pointer, 16>(integer, string); }

  template <typename T, typename Pointer>
  inline Pointer IntToBinaryString(T integer, Pointer string)
  { return IntToString<T, Pointer, 2>(integer, string); }
}
